﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;

namespace ParasiTracer
{
    class ProgramContext
    {
        static object _threadsLock = 
            new object();

        static Dictionary<int, ThreadInfo> _threads = 
            new Dictionary<int, ThreadInfo>();

        public static void inFunc (int fid)
        {
            lock (_threadsLock)
            {
                int _threadId = 
                    Thread.CurrentThread.ManagedThreadId;

                if (! _threads.ContainsKey(_threadId))
                    _threads.Add(_threadId, new ThreadInfo());

                _threads[_threadId].push(fid);
            }
        }

        public static void outFunc (int fid)
        {
            lock (_threadsLock)
            {
                int threadId =
                    Thread.CurrentThread.ManagedThreadId;

                int popedFuncId =
                    _threads[threadId].pop();

                if (popedFuncId != fid) {
                    workStackExcept(fid, popedFuncId, false);
                    while (_threads[threadId].pop() != fid)
                        ;
                }
            }
        }

        static void workStackExcept (
            int fid, int popedFuncId, bool beFatalPlease
        )
        {
            int threadId =
                Thread.CurrentThread.ManagedThreadId;

            StringBuilder sbStack = 
                new StringBuilder();

            sbStack.Append("Thread Name: ");
            sbStack.Append(Thread.CurrentThread.Name ?? string.Empty);
            sbStack.Append("\r\n");

            sbStack.Append("[");
            sbStack.Append(popedFuncId);
            sbStack.Append("] ");
            sbStack.Append(FuncTable.inst.funcs[popedFuncId].name);
            sbStack.Append("\r\n");

            foreach (int fidX in _threads[threadId].stackTrace())
            {
                sbStack.Append("[");
                sbStack.Append(fidX);
                sbStack.Append("] ");
                sbStack.Append(FuncTable.inst.funcs[fidX].name);
                sbStack.Append("\r\n");
            }
            
            string msg = string.Format (
                "quisieron popear {0} en vez de {1}!!!\r\n{2}",
                fid,
                popedFuncId,
                sbStack.ToString()
            );

            Logger.inst.logError(msg);

            if (beFatalPlease)
                throw new Exception (msg);
        }
    }
}
